import {
  useRef,
  useState,
  type ChangeEvent,
  type DragEvent,
  type ReactNode,
} from "react";
import clsm from "@/lib/utils/clsm";

type FileSelectorProps = {
  onFileChange?: (file?: File) => void;
  validator?: (file: File) => boolean;
  children?: ReactNode | ((file?: File) => ReactNode);
  className?: string | ((data: { isDragOver: boolean; file?: File }) => string);
};
export default function FileSelector(props: FileSelectorProps) {
  const { onFileChange, validator, children, className } = props;
  const [file, setFile] = useState<File>();
  const [isDragOver, setIsDragOver] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);

  function handleFileChange(e: ChangeEvent<HTMLInputElement> | File) {
    const file = e instanceof File ? e : e.target.files?.[0];
    if (file && validator?.(file) === false) {
      return;
    }
    setFile(file);
    onFileChange?.(file);
  }

  function handleDrop(e: DragEvent<HTMLDivElement>) {
    e.preventDefault();
    setIsDragOver(false);
    const file = e.dataTransfer.files[0];
    handleFileChange(file);
  }
  function handleDragEnter(e: DragEvent<HTMLDivElement>) {
    e.preventDefault();
    setIsDragOver(true);
  }
  function handleDragLeave(e: DragEvent<HTMLDivElement>) {
    setIsDragOver(false);
  }

  return (
    <div
      className={clsm(
        "cursor-pointer *:pointer-events-none",
        typeof className === "function"
          ? className({ isDragOver, file })
          : className,
      )}
      onClick={() => inputRef.current?.click()}
      onDrop={handleDrop}
      onDragOver={(e) => e.preventDefault()}
      onDragEnter={handleDragEnter}
      onDragLeave={handleDragLeave}
    >
      <input
        type="file"
        accept="image/*"
        className="!hidden"
        onChange={handleFileChange}
        ref={inputRef}
      />
      {typeof children === "function" ? children(file) : children}
    </div>
  );
}
